package com.itheima.reggie.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.itheima.reggie.common.R;
import com.itheima.reggie.entity.User;
import com.itheima.reggie.service.UserService;
import com.itheima.reggie.utils.ValidateCodeUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpSession;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author 程达
 * @PackageName:com.itheima.reggie.controller
 * @ClassName:UserController
 * @Description:前台用户验证码登录
 * @date 2022/5/29 9:40
 **/
@RestController
@Slf4j
@RequestMapping("/user")
@Api(tags = "前台用户相关接口")
public class UserController {


    @Autowired
    private UserService userService;

    @Autowired
    private RedisTemplate redisTemplate;


    /**
     * 获取验证码处理器
     * 获取手机号  生成验证码 把验证码发到手机上
     * json格式
     * {"phone":"17383673867"}
     */
    @PostMapping("/sendMsg")
    @ApiOperation(value = "前台用户获取验证码接口")
    public R<String> sendMsg(@RequestBody User user) {
        //2.获取手机号
        String phone = user.getPhone();
        //2.2生成验证码
        if (StringUtils.isNotEmpty(phone)) {//手机号不为空
            //1.获取验证码处理器 生成随机的四位验证码
            Integer code = ValidateCodeUtils.generateValidateCode(4);
            //3.把验证码发到手机上 先用控制台代替
            log.info("我们要发送给用户的验证码是:" + code);
            // 调用阿里云接口 发送验证码
            /*
            String signName = "传智健康项目基手机号登录";
            String templateCode = "SMS_175532136";
            // 通过阿里云给 指定的手机 发生指定签名+模板的验证码
            //循环 定时器 一分钟发一次
            SMSUtils.sendMessage(signName,templateCode,phone,code+"");
          */  // 测试先不发... 我们就去控制台看验证码就行

            //  这个生成的验证码要不要存到服务器中
            //  两个请求 在一个浏览器玩   把生成验证码存到会话域  代表一次会话
            //4.把验证码放到服务器域中,给后面验证比较使用

            // 不用session
            //  session.setAttribute(phone, code);//前面的键起啥名字呢
            //放到redis中
            //7.需要将生成的验证码保存到Redis,设置过期时间
            //session无法完成 其中某个数据的 过期时间
            // 我们要把手机号 和验证码 存储到 redis中  键 字符串  值 字符串
            redisTemplate.opsForValue().set(phone,code,2, TimeUnit.MINUTES);
            // 手机号:code   存储时间 2 单位 分钟
            //  字符串  --- code--用Integer的序列化形式 .toString()写出出去了
            return R.success("手机验证码发送成功,请查收");

        }

        return R.error("验证码发生失败");

    }

    /***
     * 处理登录的处理器
     *     {
     *     "phone":"132424343",
     *      "code":"2768"
     *     }
     *     这里选择用map接收，因为是前端传过来的，user没这个字段，
     *     并且这个属性值不需要存到数据库里面，只是放到session中，用来校验。
     *     不需要使用dto临时交互表，
     */
    @PostMapping("/login")
    //1.获取前端传递的手机号和验证码
    @ApiOperation(value = "前台用户登录接口")
    public R<User> login(@RequestBody Map map, HttpSession session) {
        log.info("接收到的用户登录信息 map:{}" + map);
        //1.1获取手机号
        String phone = map.get("phone").toString();
        // 1.2录入验证码
        String code = map.get("code").toString();
        // 2). 从Session中获取到手机号对应的正确的验证码  session验证码
        // String codeInSession = session.getAttribute(phone).toString();
        //2.2 优化
        //从Redis中获取缓存的验证码   // 键去取值 --  值反序列化 Integer类型反序列化的 所以反序列化回来的值 integer类型
        String codeInSession = redisTemplate.opsForValue().get(phone).toString();
        //Object codeInSession = redisTemplate.opsForValue().get(phone);//不转字符串和数值没法比较
        // 3). 进行验证码的比对 , 如果比对失败, 直接返回错误信息
        //万一 这个session中没存呢
        //if (StringUtils.isNotEmpty(codeInSession) && codeInSession.equals(code)) {
        //  存的时候类型
        // 进行比较
        if (codeInSession != null && codeInSession.equals(code)) {
            // 判断  是否 验证码和session中一样
            //用户登录成功  我们要做什么呢?
            //8.从Redis中删除缓存的验证码
            // 登录成功了 消掉
            redisTemplate.delete(phone);//登录成功 就删除
            //4). 如果比对成功, 需要根据手机号查询当前用户,
            //4.2如果用户不存在, 则自动注册一个新用户
            LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
            // 查询用户表  根据 phone手机号
            wrapper.eq(User::getPhone, phone);
            User one = userService.getOne(wrapper);

            // 4.2 没有 就是第一次登录 ---注册 保存手机号
            if (one == null) {//第一次
                one = new User();
                one.setPhone(phone);
                one.setStatus(1);
                //保存
                userService.save(one);
            }

            // 5). 将登录用户的ID存储Session中
            // 不管是不是第一次  代表用户登录成功了  成功就 把成功的用户id存到 session中
            /// 用来方便后面的权限校验
            session.setAttribute("user", one.getId());//这里存的是登录用户的id

            // 6.给前端页面返回什么呢?   返回一个 登录后的用户信息
            return R.success(one);
        }
        return R.error("验证码有误,登录失败");
    }
//    public R<String> login(@RequestBody Map map,HttpSession session){
//        map.get("phone")
//                map.get("code")
//    }
}
